package com.tools.web.filter.gateway;

import com.tools.common.object.Note;
import com.tools.common.thread.TimePair;
import com.tools.common.thread.Timeunit;
import com.tools.middle.redis.client.JedisClusterPlus;
import com.tools.web.WebKit;
import com.tools.web.interceptor.auth.AuthenticationManager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import redis.clients.jedis.JedisCluster;

import java.util.Objects;
import java.util.Set;

/**
 * 使用 JedisClusterPlus 客户端操作集群 Redis 实现的网关过滤器
 * */
@Note("使用 JedisClusterPlus 客户端操作集群 Redis 实现的网关过滤器")
public final class JedisClusterPlusGatewayManager extends AbsGatewayManager implements GatewayRedisLuaScript {

    @Note("操作集群 Redis 的客户端实例")
    private final JedisClusterPlus jedisClusterPlus;

    @Note("是否禁用所有的 REST 接口")
    private boolean disabledAllRestApi = false;

    private static final Logger LOGGER = LoggerFactory.getLogger(JedisClusterPlusGatewayManager.class);

    /* ********************************************************************************************
     *
     *         构造器
     *
     * *********************************************************************************************
     * */

    public JedisClusterPlusGatewayManager(JedisClusterPlus jedisClusterPlus, GatewaySource source) {
        this(jedisClusterPlus, source, null);
    }

    public JedisClusterPlusGatewayManager(JedisClusterPlus jedisClusterPlus, GatewaySource source, AuthenticationManager authenticationManager) {
        super(source, authenticationManager);
        this.jedisClusterPlus = Objects.requireNonNull(jedisClusterPlus);
    }

    /* ********************************************************************************************
     *
     *         实现的方法
     *
     * *********************************************************************************************
     * */

    @Override
    protected Logger protected_getLogger() {
        return LOGGER;
    }

    @Override
    protected long protected_toSubclassDomainUnitTime(TimePair addBlackerThresholdTime) {
        return Timeunit.toSecond(addBlackerThresholdTime);
    }

    @Override
    protected String protected_checkIfAddIPInBlacksAndGetTimeunitLabel(String clientIP) {
        String key = super.protected_getAddBlackSaveKey(clientIP);
        int addBlackerThreshold = super.getAddBlackerThreshold();
        long addBlackerThresholdTime = super.getAddBlackerThresholdTime();
        Integer result = (Integer) this.jedisClusterPlus.eval(HAS, 1, key, addBlackerThresholdTime, addBlackerThreshold);
        if(result != null && result == 1) return null;
        super.addInIpBlacks(clientIP);
        this.jedisClusterPlus.del(key);
        return Timeunit.SECOND.getText();
    }

    @Override
    protected void protected_setDisabledAllURIProperty(boolean all) {
        this.disabledAllRestApi = all;
    }

    @Override
    protected int protected_initDisabledURIs(Set<String> disabledURIs) {
        if(disabledURIs == null || disabledURIs.isEmpty()) return 0;
        return (int) this.jedisClusterPlus.sadd(super.getDisableURICacheKey(), disabledURIs);
    }

    @Override
    protected boolean protected_isInDisabledURIs(String uri) {
        return this.jedisClusterPlus.sismember(super.getDisableURICacheKey(), uri);
    }

    @Override
    public JedisClusterPlusGatewayManager addInDisabledURIs(String uri) {
        if(this.enabledDisabledURIs()) {
            if("*".equals(uri)) this.disabledAllRestApi = true;
            else this.jedisClusterPlus.jedisCluster().sadd(super.getDisableURICacheKey(),
                    WebKit.uriAddServerContextPath(uri, super.getServerContextPath()));
        }
        return this;
    }

    @Override
    public JedisClusterPlusGatewayManager addAllInDisabledURIs(String... uris) {
        if(this.enabledDisabledURIs()) {
            String[] newURIs = super.protected_checkAsNewURISet(uris, true);
            if(newURIs != null) this.jedisClusterPlus.jedisCluster().sadd(super.getDisableURICacheKey(), newURIs);
        }
        return this;
    }

    @Override
    public JedisClusterPlusGatewayManager addAllInDisabledURIs(Iterable<String> uris) {
        if(this.enabledDisabledURIs()) {
            String[] newURIs = super.protected_checkAsNewURISet(uris, true);
            if(newURIs == null) return this;
            this.jedisClusterPlus.jedisCluster().sadd(super.getDisableURICacheKey(), newURIs);
        }
        return this;
    }

    @Override
    public JedisClusterPlusGatewayManager removeFromDisabledURIs(String uri) {
        if(this.enabledDisabledURIs()) {
            if("*".equals(uri)) this.disabledAllRestApi = false;
            else this.jedisClusterPlus.jedisCluster().srem(super.getDisableURICacheKey(),
                    WebKit.uriAddServerContextPath(uri, super.getServerContextPath()));
        }
        return this;
    }

    @Override
    public JedisClusterPlusGatewayManager removeAllFromDisabledURIs(String... uris) {
        if(this.enabledDisabledURIs()) {
            String[] newURIs = super.protected_checkAsNewURISet(uris, false);
            if(newURIs != null) this.jedisClusterPlus.jedisCluster().srem(super.getDisableURICacheKey(), newURIs);
        }
        return this;
    }

    @Override
    public JedisClusterPlusGatewayManager removeAllFromDisabledURIs(Iterable<String> uris) {
        if(this.enabledDisabledURIs()) {
            String[] newURIs = super.protected_checkAsNewURISet(uris, false);
            if(newURIs == null) return this;
            this.jedisClusterPlus.jedisCluster().srem(super.getDisableURICacheKey(), newURIs);
        }
        return this;
    }

    @Override
    public JedisClusterPlusGatewayManager clearDisabledURIs() {
        if(this.enabledDisabledURIs()) {
            this.jedisClusterPlus.jedisCluster().del(super.getDisableURICacheKey());
        }
        return this;
    }

    @Override
    public boolean isInDisabledURIs(String uri) {
        if(this.enabledDisabledURIs()) {
            if(this.disabledAllRestApi) return true;
            return this.jedisClusterPlus.jedisCluster().sismember(super.getDisableURICacheKey(),
                    WebKit.uriAddServerContextPath(uri, super.getServerContextPath()));
        }
        return false;
    }

    @Override
    public boolean isAllInDisabledURIs(String... uris) {
        if(this.enabledDisabledURIs()) {
            if(this.disabledAllRestApi) return true;
            String[] newURIs = super.protected_checkAsNewURISet(uris, null);
            if(newURIs == null) return false;
            String disableURICacheKey = super.getDisableURICacheKey();
            JedisCluster jedisCluster = this.jedisClusterPlus.jedisCluster();
            for(String uri : newURIs) {
                if(!jedisCluster.sismember(disableURICacheKey, uri)) return false;
            }
            return true;
        }
        return false;
    }

    @Override
    public boolean isAllInDisabledURIs(Iterable<String> uris) {
        if(this.enabledDisabledURIs()) {
            if(this.disabledAllRestApi) return true;
            String[] newURIs = super.protected_checkAsNewURISet(uris, null);
            if(newURIs != null) {
                JedisCluster jedisCluster = this.jedisClusterPlus.jedisCluster();
                String disableURICacheKey = super.getDisableURICacheKey();
                for(String uri : newURIs) {
                    if(!jedisCluster.sismember(disableURICacheKey, uri)) return false;
                }
                return true;
            }
            return false;
        }
        return false;
    }

    @Override
    public boolean isAnyInDisabledURIs(String... uris) {
        if(this.enabledDisabledURIs()) {
            if(this.disabledAllRestApi) return true;
            String[] newURIs = super.protected_checkAsNewURISet(uris, null);
            if(newURIs == null) return false;
            JedisCluster jedisCluster = this.jedisClusterPlus.jedisCluster();
            String disableURICacheKey = super.getDisableURICacheKey();
            for(String uri : newURIs) {
                if(jedisCluster.sismember(disableURICacheKey, uri)) return true;
            }
        }
        return false;
    }

    @Override
    public boolean isAnyInDisabledURIs(Iterable<String> uris) {
        if(this.enabledDisabledURIs()) {
            if(this.disabledAllRestApi) return true;
            String[] newURIs = super.protected_checkAsNewURISet(uris, null);
            if(newURIs != null) {
                String disableURICacheKey = super.getDisableURICacheKey();
                JedisCluster jedisCluster = this.jedisClusterPlus.jedisCluster();
                for(String uri : newURIs) {
                    if(jedisCluster.sismember(disableURICacheKey, uri)) return true;
                }
            }
            return false;
        }
        return false;
    }

    /* ********************************************************************************************
     *
     *         重写的方法
     *
     * *********************************************************************************************
     * */

    @Override
    public JedisClusterPlusGatewayManager addInProxyWhites(String remote) {
        super.addInProxyWhites(remote);
        return this;
    }

    @Override
    public JedisClusterPlusGatewayManager addAllInProxyWhites(String... remotes) {
        super.addAllInProxyWhites(remotes);
        return this;
    }

    @Override
    public JedisClusterPlusGatewayManager addAllInProxyWhites(Iterable<String> remotes) {
        super.addAllInProxyWhites(remotes);
        return this;
    }

    @Override
    public JedisClusterPlusGatewayManager removeFromProxyWhites(String remote) {
        super.removeFromProxyWhites(remote);
        return this;
    }

    @Override
    public JedisClusterPlusGatewayManager removeAllFromProxyWhites(String... remotes) {
        super.removeAllFromProxyWhites(remotes);
        return this;
    }

    @Override
    public JedisClusterPlusGatewayManager removeAllFromProxyWhites(Iterable<String> remotes) {
        super.removeAllFromProxyWhites(remotes);
        return this;
    }

    @Override
    public JedisClusterPlusGatewayManager clearProxyWhites() {
        super.clearProxyWhites();
        return this;
    }

    @Override
    public JedisClusterPlusGatewayManager addInIpWhites(String clientIP) {
        super.addInIpWhites(clientIP);
        return this;
    }

    @Override
    public JedisClusterPlusGatewayManager addAllInIpWhites(String... clientIPs) {
        super.addAllInIpWhites(clientIPs);
        return this;
    }

    @Override
    public JedisClusterPlusGatewayManager addAllInIpWhites(Iterable<String> clientIPs) {
        super.addAllInIpWhites(clientIPs);
        return this;
    }

    @Override
    public JedisClusterPlusGatewayManager removeFromIpWhites(String clientIP) {
        super.removeFromIpWhites(clientIP);
        return this;
    }

    @Override
    public JedisClusterPlusGatewayManager removeAllFromIpWhites(String... clientIPs) {
        super.removeAllFromIpWhites(clientIPs);
        return this;
    }

    @Override
    public JedisClusterPlusGatewayManager removeAllFromIpWhites(Iterable<String> clientIPs) {
        super.removeAllFromIpWhites(clientIPs);
        return this;
    }

    @Override
    public JedisClusterPlusGatewayManager clearIpWhites() {
        super.clearIpWhites();
        return this;
    }

    @Override
    public JedisClusterPlusGatewayManager addInIpBlacks(String clientIP) {
        super.addInIpBlacks(clientIP);
        return this;
    }

    @Override
    public JedisClusterPlusGatewayManager addInIpBlacks(String... clientIPs) {
        super.addInIpBlacks(clientIPs);
        return this;
    }

    @Override
    public JedisClusterPlusGatewayManager addInIpBlacks(Iterable<String> clientIPs) {
        super.addInIpBlacks(clientIPs);
        return this;
    }

    @Override
    public JedisClusterPlusGatewayManager removeFromIpBlacks(String clientIP) {
        super.removeFromIpBlacks(clientIP);
        return this;
    }

    @Override
    public JedisClusterPlusGatewayManager removeAllFromIpBlacks(String... clientIPs) {
        super.removeAllFromIpBlacks(clientIPs);
        return this;
    }

    @Override
    public JedisClusterPlusGatewayManager removeAllFromIpBlacks(Iterable<String> clientIPs) {
        super.removeAllFromIpBlacks(clientIPs);
        return this;
    }

    @Override
    public JedisClusterPlusGatewayManager clearIpBlacks() {
        super.clearIpBlacks();
        return this;
    }
}
